package org.onion.pattern.kit.common.jackson.serializer;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 在 web mvc 处理处理序列化及反序列化
 */
public class WebMvcObjectMapper extends ObjectMapper {
    //    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    /**
     * 是否序列化为null 的key
     */
    @Setter
    @Getter
    private Boolean serializerNonNullKey;

    @Setter
    @Getter
    private String timeZone; //"Asia/Shanghai"

    public WebMvcObjectMapper() {
        super();

        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)   //收到未知属性时不报异常
                .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)   // 允许单引号
                .configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true) //将枚举输出为字符串（而不是索引）
                .setTimeZone(TimeZone.getTimeZone(StringUtils.defaultIfBlank(this.timeZone, "UTC"))); //时区处理

        if (ObjectUtils.getIfNull(serializerNonNullKey, true)) {
            this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        }

        this.getDeserializationConfig()
//                .withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)   //反序列化时，属性不存在的兼容处理
                .withoutFeatures(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL); //枚举不匹配，不报异常

        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer())
                .addDeserializer(LocalDate.class, new LocalDateDeserializer())
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance) // 特殊指定long类型json转换的时候转成字符串形式,防止前端long类型数据精度丢失

                .addSerializer(LocalDateTime.class, new LocalDateTime2TimestampSerializer()) //转时间戳
                .addSerializer(LocalDate.class, new LocalDate2TimestampSerializer())
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        ;
        //注册功能模块 例如，可以添加自定义序列化器和反序列化器
        this.registerModules(new JavaTimeModule(), simpleModule);
    }
}
